﻿using IP2Region.Net.XDB;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Polaris.Common;
using Polaris.Common.RedisHelper;
using Polaris.Domain.Interfaces.Admin;
using Polaris.Domain.Model.DbEntity;
using Polaris.Domain.Model.Dto.Notes.Response;
using Polaris.Domain.Model.Dto.Sys_Dictionary.Response;
using Polaris.Domain.Model.Dto.Sys_User.Request;
using Polaris.Domain.Model.Dto.Sys_User.Response;
using Polaris.Domain.Model.Entity.Base;
using Polaris.Domain.Model.Entity.Exception;
using Polaris.Domain.Repository.Interfaces;
using Polaris.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Polaris.Infrastructure.DomainService.Admin
{
    public class Sys_UserService : ISys_User
    {
        private readonly IBaseRepository<Sys_User> _sysUser;
        private readonly IBaseRepository<Sys_MenuRole> _sysMenuRole;
        private readonly IBaseRepository<Sys_UserMenu> _sysUserMenu;
        private readonly PolarisDbContext _dbContext;
        private readonly string _md5Key = AppConfig.GetConfigInfo("MD5Key");
        private readonly string _baseKey = "sys:user";

        public Sys_UserService(IBaseRepository<Sys_User> sysUser, IBaseRepository<Sys_MenuRole> sysMenuRole, IBaseRepository<Sys_UserMenu> sysUserMenu, PolarisDbContext dbContext)
        {
            _sysUser = sysUser;
            _sysMenuRole = sysMenuRole;
            _sysUserMenu = sysUserMenu;
            _dbContext = dbContext;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="login"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task<TokenUserInfoResponse> Login(LoginRequest login)
        {
            var newPwd = MD5Handler.Encrypt(login.Password, _md5Key);
            var user = (await _sysUser.WhereLoadEntityAsync(d => d.Account == login.Account && d.Password == newPwd && !d.IsDelete))
                        ?? throw new CustomException(Domain.Model.Enum.ResultCode.NO_DATA, "账号或密码错误");
            if (!user.Enable)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.NO_DATA, "该账号已被禁用");
            }
            var userRoleList = await _sysUserMenu.QueryAll(u => u.UserId == user.Id).Select(u => u.MenuId.ToString()).ToListAsync();
            if (userRoleList.Count == 0)
            {
                userRoleList = await _sysMenuRole.QueryAll(m => m.RoleId == user.UserRole).Select(m => m.MenuId.ToString()).ToListAsync();
            }
            return new TokenUserInfoResponse()
            {
                UserId = user.Id.ToString(),
                Account = user.Account,
                Head = user.Head,
                UserName = user.UserName
            };
        }

        /// <summary>
        /// 创建用户
        /// </summary>
        /// <param name="create"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task CreateUser(CreateUserInfoRequest create, Guid? userId)
        {
            var cacheKey = $"{_baseKey}:query:*";
            await RedisHelper.DeleteKeysByPatternAsync(cacheKey);

            var newPwd = MD5Handler.Encrypt(create.Password, _md5Key);
            var user = new Sys_User()
            {
                Account = create.Account,
                Password = newPwd,
                CreateBy = userId,
                CreatedTime = DateTime.Now,
                Enable = create.Enable,
                Id = Guid.NewGuid(),
                Head = create.Head,
                UserName = create.UserName,
                UserRole = create.UserRole != null ? Guid.Parse(create.UserRole) : null,
            };
            await _sysUser.AddEntityAsync(user);
            await _sysUser.CommitAsync();

            await Task.Delay(500);
            await RedisHelper.DeleteKeysByPatternAsync(cacheKey);
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="id"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task DeleteUserById(string id, Guid? userId)
        {
            var cacheKey = $"{_baseKey}:query:*";
            await RedisHelper.DeleteKeysByPatternAsync(cacheKey);

            var user = await _sysUser.QueryAll(d => d.Id == Guid.Parse(id)).FirstOrDefaultAsync();
            if (user == null)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.NO_DATA, "未找到数据");
            }

            user.IsDelete = true;
            user.UpdatedBy = userId;
            user.UpdatedTime = DateTime.Now;
            _sysUser.UpdateEntity(user);
            await _sysUser.CommitAsync();

            await Task.Delay(500);
            await RedisHelper.DeleteKeysByPatternAsync(cacheKey);
        }

        /// <summary>
        /// 根据id获取用户信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<UpdateUserInfoRequest> GetUserById(string id)
        {
            var user = await _sysUser.QueryAll(d => d.Id == Guid.Parse(id))
                .Select(d => new UpdateUserInfoRequest()
                {
                    Id = d.Id.ToString(),
                    Account = d.Account,
                    Head = d.Head,
                    Password = d.Password,
                    UserName = d.UserName,
                    UserRole = d.UserRole.ToString(),
                    Enable = d.Enable
                }).FirstOrDefaultAsync();
            if (user == null)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.NO_DATA, "未找到数据");
            }
            user.Password = MD5Handler.Decrypt(user.Password, _md5Key);
            return user;
        }

        /// <summary>
        /// 修改用户信息
        /// </summary>
        /// <param name="update"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task UpdateUser(UpdateUserInfoRequest update, Guid? userId)
        {
            try
            {
                var user = await _sysUser.QueryAll(d => d.Id == Guid.Parse(update.Id)).FirstOrDefaultAsync();
                if (user == null)
                {
                    throw new CustomException(Domain.Model.Enum.ResultCode.NO_DATA, "未找到数据");
                }
                var newPwd = MD5Handler.Encrypt(update.Password, _md5Key);
                user.Password = newPwd;
                user.Account = update.Account;
                user.UpdatedBy = userId;
                user.UpdatedTime = DateTime.Now;
                user.Head = update.Head;
                user.UserName = update.UserName;
                user.UserRole = Guid.Parse(update.UserRole);
                user.Enable = update.Enable;

                _sysUser.UpdateEntity(user);
                await _sysUser.CommitAsync();
            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }
        }

        /// <summary>
        /// 获取用户列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<PaginationInfo<UserInfoResponse>> GetUserList(UserInfoQueryRequest query)
        {
            try
            {
                var cacheKey1 = $"{_baseKey}:query:*";
                await RedisHelper.DeleteKeysByPatternAsync(cacheKey1);
                var cacheKey = $"{_baseKey}:query::page:{query.PageIndex}:size:{query.PageSize}";

                var redisData = await RedisHelper.GetPaginationAsync<UserInfoResponse>(cacheKey);
                if (redisData != null)
                {
                    return redisData;
                }
                else
                {
                    int total = 0;
                    var userList = await _sysUser.QueryAll(out total, query.PageIndex, query.PageSize, u => u.CreatedTime, false, u => !u.IsDelete).Select(u => new UserInfoResponse()
                    {
                        Account = u.Account,
                        CreateTime = u.CreatedTime.HasValue ? u.CreatedTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
                        Enable = u.Enable,
                        Id = u.Id,
                        Head = u.Head,
                        UserName = u.UserName,
                        LastLoginIP = u.LastLoginIP,
                        LastLoginTime = u.LastLoginTime,
                        UpdateTime = u.UpdatedTime.HasValue ? u.UpdatedTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
                    }).ToListAsync();

                    var userIds = userList.Select(u => u.Id).ToList();
                    var userMenuList = await _sysUserMenu.QueryAll(m => userIds.Contains(m.UserId)).Select(m => m.UserId).ToListAsync();
                    var notIncluded = userIds.Where(d => !userMenuList.Contains(d)).ToList();

                    var linqStr = from user in _dbContext.Sys_User
                                  where notIncluded.Contains(user.Id)
                                  join role in _dbContext.Sys_Role on user.UserRole equals role.Id
                                  select new
                                  {
                                      userId = user.Id,
                                      roleName = role.Name,
                                  };
                    var roleList = linqStr.ToList();
                    userList.ForEach(item =>
                    {
                        if (userMenuList.Where(d => d == item.Id).Any())
                        {
                            item.UserRole = "自定义授权";
                        }
                        else if (roleList.Where(d => d.userId == item.Id).Any())
                        {
                            item.UserRole = roleList.Where(d => d.userId == item.Id).FirstOrDefault().roleName;
                        }
                    });
                    var result = ApiResult
                            .CreatePaginationInfo<UserInfoResponse>(
                                                                PageIndex: query.PageIndex,
                                                                PageSize: query.PageSize,
                                                                Total: total,
                                                                Result: userList
                                                                );
                    await RedisHelper.CachePaginationAsync(cacheKey, result);
                    return result;
                }

            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }
        }
    }
}
